package management

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strconv"
	"time"

	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"github.com/jsrccb/nachuan/common"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type UserMgr struct {
	client         *mongo.Client
	userCollection *mongo.Collection
}

var (
	G_userMgr *UserMgr
)

func (userMgr *UserMgr) checkUser(userFilter *common.UserFilter) (userinfo *common.UserInfo, err error) {

	var (
		resultOne *mongo.SingleResult
	)

	resultOne = userMgr.userCollection.FindOne(context.TODO(), userFilter, &options.FindOneOptions{})

	resultOne.Decode(&userinfo)
	// fmt.Println(userinfo)

	return
}

func (userMgr *UserMgr) updUserPwd(phoneno string, oldpwd string, newpwd string) (err error) {

	var (
		userphoneFilter *common.UserPhoneFilter
		userFilter      *common.UserFilter
		usercount       int64
	)
	userphoneFilter = &common.UserPhoneFilter{
		PhoneNo: phoneno,
	}
	userFilter = &common.UserFilter{
		PhoneNo:  phoneno,
		PassWord: oldpwd,
	}

	if usercount, _ = userMgr.userCollection.CountDocuments(context.TODO(), userFilter); usercount > 0 {
		userMgr.userCollection.UpdateOne(context.TODO(), userphoneFilter, bson.M{"$set": bson.M{"passWord": newpwd, "passWordSts": "已修改"}})
	}
	// filter = &common.UserPhoneFilter{
	// 	PhoneNo: phoneno,
	// }
	// if _,err = userMgr.userCollection.(context.TODO(), userFilter, bson.M{"$set": bson.M{"passWord": newpwd}); err != nil {
	// 	return
	// }
	return
}

func (userMgr *UserMgr) delUser(phoneno string) (err error) {

	var (
		userFilter *common.UserPhoneFilter
	)
	userFilter = &common.UserPhoneFilter{
		PhoneNo: phoneno,
	}
	// filter = &common.UserPhoneFilter{
	// 	PhoneNo: phoneno,
	// }
	if _, err = userMgr.userCollection.DeleteOne(context.TODO(), userFilter); err != nil {
		return
	}
	return
}

func (userMgr *UserMgr) checkUserPhoneno(userFilter *common.UserPhoneFilter) (userExit bool, err error) {

	var (
		doccount int64
	)

	if doccount, err = userMgr.userCollection.CountDocuments(context.TODO(), userFilter); err != nil {

		return
	}

	if doccount > 0 {
		userExit = true
	} else {
		userExit = false
	}
	return
}

func (userMgr *UserMgr) checkUserPhonenoAdmin(userFilter *common.UserPhoneAdminFilter) (userExit bool, err error) {

	var (
		doccount int64
	)

	if doccount, err = userMgr.userCollection.CountDocuments(context.TODO(), userFilter); err != nil {

		return
	}

	if doccount > 0 {
		userExit = true
	} else {
		userExit = false
	}
	return
}

func (userMgr *UserMgr) CountUser() (usercount int64, err error) {
	var (
		ctx context.Context
	)
	ctx, _ = context.WithTimeout(context.Background(), 15*time.Second)

	usercount, err = userMgr.userCollection.CountDocuments(ctx, bson.M{})
	return
}

func (userMgr *UserMgr) ListUser(skip int64, limit int64) (userArr []*common.UserInfo, err error) {

	var (
		cursor   *mongo.Cursor
		findopt  *options.FindOptions
		ctx      context.Context
		userInfo *common.UserInfo
	)

	//预防查询不到结果返回nil，这样返回是空数组
	userArr = make([]*common.UserInfo, 0)

	ctx, _ = context.WithTimeout(context.Background(), 10*time.Second)

	if limit > 0 && skip >= 0 {
		findopt = &options.FindOptions{}
		findopt.SetLimit(limit)
		findopt.SetSkip(limit * skip)

	} else {
		return
	}
	if cursor, err = userMgr.userCollection.Find(ctx, bson.M{}, findopt); err != nil {
		return
	}
	// fmt.Print(cursor)
	defer cursor.Close(ctx)

	//反序列化到bson
	for cursor.Next(ctx) {
		userInfo = &common.UserInfo{}
		if err = cursor.Decode(userInfo); err != nil {
			continue
		}
		if userInfo != nil {
			userInfo.PassWord = "******"
		}
		// fmt.Println(jobLog)
		userArr = append(userArr, userInfo)
	}
	return
}

func (userMgr *UserMgr) getUserInfo(userFilter *common.UserPhoneFilter) (userinfo *common.UserInfo) {

	userMgr.userCollection.FindOne(context.TODO(), userFilter).Decode(&userinfo)
	if userinfo != nil {
		userinfo.PassWord = "******"
	}

	return
}

func (userMgr *UserMgr) getUserInfoByDept(userFilter *common.UserDeptFilter) (userArr []*common.UserInfo) {
	var (
		cursor   *mongo.Cursor
		ctx      context.Context
		err      error
		userinfo *common.UserInfo
	)
	if cursor, err = userMgr.userCollection.Find(ctx, userFilter); err != nil {
		return
	}
	defer cursor.Close(ctx)

	//反序列化到bson
	for cursor.Next(ctx) {
		userinfo = &common.UserInfo{}
		if err = cursor.Decode(userinfo); err != nil {
			continue
		}
		if userinfo != nil {
			userinfo.PassWord = "******"
		}
		// fmt.Println(jobLog)
		userArr = append(userArr, userinfo)
	}
	return
}

func (userMgr *UserMgr) getUserInfoByRole(userrole string) (userArr []*common.UserInfo) {
	var (
		cursor    *mongo.Cursor
		ctx       context.Context
		err       error
		userinfo  *common.UserInfo
		querySet  []bson.M
		queryBson bson.M
	)

	if userrole != "" {
		q_userrole := bson.M{"userRoles": bson.M{"$regex": userrole, "$options": "$i"}}
		querySet = append(querySet, q_userrole)
	}

	queryBson = bson.M{"$and": querySet}

	if cursor, err = userMgr.userCollection.Find(ctx, queryBson); err != nil {
		return
	}
	defer cursor.Close(ctx)

	//反序列化到bson
	for cursor.Next(ctx) {
		userinfo = &common.UserInfo{}
		if err = cursor.Decode(userinfo); err != nil {
			continue
		}
		if userinfo != nil {
			userinfo.PassWord = "******"
		}
		// fmt.Println(jobLog)
		userArr = append(userArr, userinfo)
	}
	return
}

func (userMgr *UserMgr) saveUser(userInfo *common.UserInfo) (userinfo *common.UserInfo, err error) {

	var (
		// resultOne *mongo.InsertOneResult
		filter   *common.UserPhoneFilter
		doccount int64
		// update *common.HostInfo
	)

	filter = &common.UserPhoneFilter{
		PhoneNo: userInfo.PhoneNo,
	}

	userInfo.CreateTime = common.BuildTimeNowStr()

	if doccount, err = userMgr.userCollection.CountDocuments(context.TODO(), filter); err != nil {
		return
	}

	// fmt.Println(doccount)
	if doccount > 0 {
		userMgr.userCollection.FindOneAndUpdate(context.TODO(), filter, bson.M{"$set": userInfo})
	} else {
		userMgr.userCollection.InsertOne(context.TODO(), userInfo)
	}

	return
}

func (userMgr *UserMgr) updUserNoPasswd(userInfo *common.UserInfo) (userinfo *common.UserInfo, err error) {

	var (
		// resultOne *mongo.InsertOneResult
		filter *common.UserPhoneFilter
		// update *common.HostInfo
		tmpUser *common.UserInfo
	)

	filter = &common.UserPhoneFilter{
		PhoneNo: userInfo.PhoneNo,
	}

	// userInfo.CreateTime = common.BuildTimeNowStr()

	userMgr.userCollection.FindOne(context.TODO(), filter).Decode(&tmpUser)

	// fmt.Println(doccount)
	if tmpUser != nil {

		userInfo.PassWord = tmpUser.PassWord
		userMgr.userCollection.FindOneAndUpdate(context.TODO(), filter, bson.M{"$set": userInfo})
	}

	return
}

func initUserApi(r *mux.Router) {
	s := r.PathPrefix("/user").Subrouter()

	// s.HandleFunc("/list", UserListHandler)
	s.HandleFunc("/add", handleUserAdd)
	s.HandleFunc("/upd", handleUserUpd)
	s.HandleFunc("/del", handleUserDel)
	s.HandleFunc("/signin", handleUserSignIn)
	s.HandleFunc("/signout", handleUserSignOut)
	s.HandleFunc("/useraddonce", handleUserAddOnce)
	s.HandleFunc("/upduserpwd", handleUserPwdUpd)

	//请求/user/query?phoneno=18963601153
	s.HandleFunc("/query", handleUserQuery)
	//请求/user/query?dept=18963601153
	s.HandleFunc("/querybydept", handleUserQueryByDept)
	s.HandleFunc("/querybyrole", handleUserQueryByRole)

	//请求/user/queryall?skip=0&limit=10
	s.HandleFunc("/queryall", handleQueryAllBySkip)
}

func handleQueryAllBySkip(resp http.ResponseWriter, req *http.Request) {
	var (
		err        error
		bytes      []byte
		userinfo   []*common.UserInfo
		skipParam  string
		limitParam string
		skip       int
		limit      int
		usercount  int64
	)

	query := req.URL.Query()
	skipParam = query.Get("skip")
	limitParam = query.Get("limit")
	if skip, err = strconv.Atoi(skipParam); err != nil {
		skip = 0
	}

	if limit, err = strconv.Atoi(limitParam); err != nil {
		limit = 100
	}

	userinfo, _ = G_userMgr.ListUser(int64(skip), int64(limit))
	usercount, _ = G_userMgr.CountUser()

	usermap := make(map[string]interface{})
	usermap["usercount"] = usercount
	usermap["userinfo"] = userinfo

	if userinfo != nil {
		if bytes, err = common.BuildResponse(0, "success", usermap); err == nil {
			resp.Write(bytes)
		}
	} else {
		if bytes, err = common.BuildResponse(-1, "error", "用户不存在"); err == nil {
			resp.Write(bytes)
		}
	}
	return
}

func handleUserQueryByRole(resp http.ResponseWriter, req *http.Request) {
	var (
		err      error
		bytes    []byte
		rolename string
		userinfo []*common.UserInfo
	)

	query := req.URL.Query()
	rolename = query.Get("rolename")

	userinfo = G_userMgr.getUserInfoByRole(rolename)

	if userinfo != nil {
		if bytes, err = common.BuildResponse(0, "success", userinfo); err == nil {
			resp.Write(bytes)
		}
	} else {
		if bytes, err = common.BuildResponse(-1, "error", "用户不存在"); err == nil {
			resp.Write(bytes)
		}
	}
	return
}

func handleUserQueryByDept(resp http.ResponseWriter, req *http.Request) {
	var (
		err      error
		bytes    []byte
		dept     string
		filter   *common.UserDeptFilter
		userinfo []*common.UserInfo
	)

	query := req.URL.Query()
	dept = query.Get("dept")

	filter = &common.UserDeptFilter{
		UserDept: dept,
	}
	userinfo = G_userMgr.getUserInfoByDept(filter)

	if userinfo != nil {
		if bytes, err = common.BuildResponse(0, "success", userinfo); err == nil {
			resp.Write(bytes)
		}
	} else {
		if bytes, err = common.BuildResponse(-1, "error", "用户不存在"); err == nil {
			resp.Write(bytes)
		}
	}
	return
}
func handleUserQuery(resp http.ResponseWriter, req *http.Request) {
	var (
		err         error
		bytes       []byte
		phoneno     string
		filter      *common.UserPhoneFilter
		userinfo    *common.UserInfo
		roleinfoarr []*common.RoleLimits
	)

	query := req.URL.Query()
	phoneno = query.Get("phoneno")

	filter = &common.UserPhoneFilter{
		PhoneNo: phoneno,
	}
	userinfo = G_userMgr.getUserInfo(filter)
	if userinfo != nil {
		usermap := make(map[string]interface{})
		userjson, _ := json.Marshal(userinfo)
		json.Unmarshal(userjson, &usermap)
		roleinfoarr, _ = G_roleMgr.queryRoleLimitsInfo(userinfo.UserType)
		usermap["rolelimits"] = roleinfoarr
		if bytes, err = common.BuildResponse(0, "success", usermap); err == nil {
			resp.Write(bytes)
		}
	} else {
		if bytes, err = common.BuildResponse(-1, "error", "用户不存在"); err == nil {
			resp.Write(bytes)
		}
	}
	return
}

func InitUserMgr() (err error) {
	var (
		client *mongo.Client
	)
	client, err = mongo.NewClient(options.Client().ApplyURI(G_config.MongodbUri).SetMaxPoolSize(2))
	if err != nil {
		err = err
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(G_config.MongodbConnectTimeout)*time.Millisecond)
	defer cancel()
	err = client.Connect(ctx)
	if err != nil {
		err = err
	}

	G_userMgr = &UserMgr{
		client:         client,
		userCollection: client.Database(G_config.AppDBName).Collection("user"),
	}

	// fmt.Println("init userMgr")

	return
}
func handleUserSignIn(resp http.ResponseWriter, req *http.Request) {

	var (
		err         error
		userFilter  *common.UserFilter
		bytes       []byte
		userinfo    *common.UserInfo
		roleinfoarr []*common.RoleLimits
	)

	switch req.Method {

	case "GET":
		//io.WriteString(w, s string) 将字符串的
	case "POST":
		userFilter = &common.UserFilter{
			PhoneNo:  req.PostFormValue("phoneno"),
			PassWord: req.PostFormValue("password"),
		}
	}

	fmt.Println(userFilter)
	//验证过期设置
	if G_config.DateOut < common.BuildDateTodayStr4() {
		if bytes, err = common.BuildResponse(-1, "登陆异常", "系统使用期限"); err == nil {
			resp.Write(bytes)
		}
		return
	}

	if userinfo, err = G_userMgr.checkUser(userFilter); err != nil {
		goto ERR
	}

	// fmt.Println(userStatus, err)
	// 返回正常的应答
	if userinfo != nil && (userinfo.UserStatus == "试用期在职" || userinfo.UserStatus == "正式在职") {
		//设置sessions
		// if userinfo != nil {

		if session, err := sessionStore.Get(req, common.SESSIONUSER); err != nil {
			goto ERR
		} else {
			session.Options = &sessions.Options{
				Path:   "/",
				MaxAge: common.SESSIONMAX, // 以秒为单位
			}
			session.Values["username"] = req.PostFormValue("phoneno")
			session.Save(req, resp)
		}

		usermap := make(map[string]interface{})
		userjson, _ := json.Marshal(userinfo)
		json.Unmarshal(userjson, &usermap)
		roleinfoarr, _ = G_roleMgr.queryRoleLimitsInfo(userinfo.UserType)
		usermap["rolelimits"] = roleinfoarr
		usermap["dateout"] = G_config.DateOut
		usermap["usercount"] = G_config.UserCount

		if bytes, err = common.BuildResponse(0, "success", usermap); err == nil {
			resp.Write(bytes)
		}
	} else {

		if bytes, err = common.BuildResponse(-1, "登陆异常", "请检查用户状态或密码"); err == nil {
			resp.Write(bytes)
		}
	}
	return
ERR:
	if bytes, err = common.BuildResponse(-1, err.Error(), nil); err == nil {
		resp.Write(bytes)
	}
}

func handleUserSignOut(resp http.ResponseWriter, req *http.Request) {
	var (
		err   error
		bytes []byte
	)

	if session, err := sessionStore.Get(req, common.SESSIONUSER); err != nil {
		goto ERR
	} else {
		session.Values["username"] = ""
		session.Save(req, resp)
		fmt.Println(session.Values["username"])
	}
	if bytes, err = common.BuildResponse(0, "success", "正常退出"); err == nil {
		resp.Write(bytes)
	}
	return
ERR:
	if bytes, err = common.BuildResponse(-1, err.Error(), "签退异常"); err == nil {
		resp.Write(bytes)
	}
}

func handleUserUpd(resp http.ResponseWriter, req *http.Request) {

	var (
		err          error
		phoneno      interface{}
		userStatus   bool
		userinfo     *common.UserInfo
		postuserinfo string
		session      *sessions.Session
	)

	if session, err = sessionStore.Get(req, common.SESSIONUSER); err != nil {
		goto ERR
	} else {

		phoneno = session.Values["username"]
		if phoneno != nil {
			userFilter := &common.UserPhoneFilter{
				PhoneNo: phoneno.(string),
			}
			if userStatus, err = G_userMgr.checkUserPhoneno(userFilter); err != nil {
				goto ERR
			}
			if userStatus {
				if err = req.ParseForm(); err != nil {
					goto ERR
				}
				postuserinfo = req.PostForm.Get("userinfo")
				// fmt.Println(postJob)
				if err = json.Unmarshal([]byte(postuserinfo), &userinfo); err != nil {
					goto ERR
				}

				G_userMgr.updUserNoPasswd(userinfo)

				if bytes, err := common.BuildResponse(0, "success", "用户更新成功"); err == nil {
					resp.Write(bytes)
				}
				return
			}
		}
		if bytes, err := common.BuildResponse(-1, "error", "用户更新异常"); err == nil {
			resp.Write(bytes)
		}
	}
	return
ERR:
	if bytes, err := common.BuildResponse(-1, err.Error(), "用户更新异常"); err == nil {
		resp.Write(bytes)
	}
}
func handleUserAdd(resp http.ResponseWriter, req *http.Request) {

	var (
		err          error
		phoneno      interface{}
		userStatus   bool
		userinfo     *common.UserInfo
		postuserinfo string
		session      *sessions.Session
		usercount    int64
	)

	if session, err = sessionStore.Get(req, common.SESSIONUSER); err != nil {
		goto ERR
	} else {

		phoneno = session.Values["username"]
		if phoneno != nil {
			userFilter := &common.UserPhoneFilter{
				PhoneNo: phoneno.(string),
			}
			if userStatus, err = G_userMgr.checkUserPhoneno(userFilter); err != nil {
				goto ERR
			}
			if userStatus {
				if err = req.ParseForm(); err != nil {
					goto ERR
				}
				postuserinfo = req.PostForm.Get("userinfo")
				// fmt.Println(postJob)
				if err = json.Unmarshal([]byte(postuserinfo), &userinfo); err != nil {
					goto ERR
				}

				usercount, _ = G_userMgr.CountUser()
				if int64(G_config.UserCount) <= usercount {
					if bytes, err := common.BuildResponse(-1, "error", "用户数量超过"); err == nil {
						resp.Write(bytes)
					}
					return
				}
				G_userMgr.saveUser(userinfo)

				if bytes, err := common.BuildResponse(0, "success", "用户新增成功"); err == nil {
					resp.Write(bytes)
				}
				return
			}
		}
		if bytes, err := common.BuildResponse(-1, "error", "用户新增异常"); err == nil {
			resp.Write(bytes)
		}
	}
	return
ERR:
	if bytes, err := common.BuildResponse(-1, err.Error(), "用户新增异常"); err == nil {
		resp.Write(bytes)
	}
}

func handleUserPwdUpd(resp http.ResponseWriter, req *http.Request) {

	var (
		phoneno    string
		oldpwd     string
		newpwd     string
		err        error
		userFilter *common.UserFilter
		userinfo   *common.UserInfo
	)

	if err = req.ParseForm(); err != nil {
		goto ERR
	}
	phoneno = req.PostForm.Get("phoneno")
	oldpwd = req.PostForm.Get("oldpwd")
	newpwd = req.PostForm.Get("newpwd")
	// fmt.Println(phoneno, oldpwd, newpwd)

	userFilter = &common.UserFilter{
		PhoneNo:  phoneno,
		PassWord: oldpwd,
	}

	// fmt.Println(userFilter)

	if userinfo, err = G_userMgr.checkUser(userFilter); userinfo == nil {
		// fmt.Println(err)
		goto ERR
	} else {
		G_userMgr.updUserPwd(phoneno, oldpwd, newpwd)
	}

	// G_userMgr.checkUserPhoneno()(phoneno)

	if bytes, err := common.BuildResponse(0, "success", "密码更新成功"); err == nil {
		resp.Write(bytes)
	}
	return
ERR:
	if bytes, err := common.BuildResponse(-1, "error", "用户密码更新异常"); err == nil {
		resp.Write(bytes)
	}
}

func handleUserDel(resp http.ResponseWriter, req *http.Request) {

	var (
		phoneno string
	)

	query := req.URL.Query()
	phoneno = query.Get("phoneno")
	// fmt.Println(postJob)

	G_userMgr.delUser(phoneno)

	if bytes, err := common.BuildResponse(0, "success", "用户删除成功"); err == nil {
		resp.Write(bytes)
	}
	return
}

func handleUserAddOnce(resp http.ResponseWriter, req *http.Request) {

	var (
		err          error
		userinfo     *common.UserInfo
		postuserinfo string
	)

	if err = req.ParseForm(); err != nil {
		goto ERR
	}
	postuserinfo = req.PostForm.Get("userinfo")
	// fmt.Println(postuserinfo)
	if err = json.Unmarshal([]byte(postuserinfo), &userinfo); err != nil {
		goto ERR
	}

	if _, err = G_userMgr.saveUser(userinfo); err != nil {
		goto ERR
	}

	if bytes, err := common.BuildResponse(0, "success", "用户新增成功"); err == nil {
		resp.Write(bytes)
	}

	return

ERR:
	if bytes, err := common.BuildResponse(-1, err.Error(), "用户新增异常"); err == nil {
		resp.Write(bytes)
	}
}
